package com.yiji.fintech.musfinance.common.factory.domain;

import com.acooly.core.common.facade.OrderBase;
import com.yiji.fintech.musfinance.common.annotation.Order2Domain2Event;
import com.yiji.fintech.musfinance.common.domain.base.BaseDomain;
import com.yiji.fintech.musfinance.common.exception.AbortBizException;
import com.yiji.fintech.musfinance.common.exception.Order2DomainException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.stereotype.Service;

import java.util.Set;

/**
 * Created by ouwen@yiji.com} on 2017/9/13.
 */
@Slf4j
@Service
public class DomainFactory extends AbstractBaseFactory implements ApplicationContextAware, InitializingBean {

    private ApplicationContext applicationContext;
    private String scanBasePath = "com.yiji.fintech.musfinance";

    @Override
    protected BaseDomain factory(OrderBase orderBase) {
        Class domain = ORDER2DOMAIN.get(orderBase.getClass());
        if(domain != null){
            try {
                return (BaseDomain)domain.newInstance();
            }  catch (Exception e) {
                throw new Order2DomainException(e.getMessage());
            }
        }else{
            throw new AbortBizException("Order转换Domain异常：未查找到Order【"+orderBase.getClass()+"】对应的Domain配置");
        }
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        //获取Order和Domain对应关系
        scanDomainOrder();
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
    /**
     * 扫描Domain注解Order关系
     */
    private void scanDomainOrder(){
        ClassPathScanningCandidateComponentProvider provider =
                new ClassPathScanningCandidateComponentProvider(false);
        provider.addIncludeFilter(new AnnotationTypeFilter(Order2Domain2Event.class));
        Set<BeanDefinition> components = provider.findCandidateComponents(scanBasePath);
        for (BeanDefinition component : components) {
            try {
                Class domain = Class.forName(component.getBeanClassName());
                Order2Domain2Event annotation = (Order2Domain2Event)domain.getAnnotation(Order2Domain2Event.class);
                ORDER2DOMAIN.put(annotation.orderClass(),domain);
            } catch (ClassNotFoundException e) {
                log.error("扫描Domain与Order关系异常【{}】",e.getMessage());
            }catch (Exception e){
                log.error("未知异常【{}】",e.getMessage());
            }
        }
    }
}
